﻿using Device;
using IotClientApp.Server.Hubs;
using IotClientApp.Server.MqttClient;
using IotClientApp.Shared;
using IotModel;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.SS.UserModel;
using PLC.ModBusMaster;
using PluginInterface;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using IClientProxy = Microsoft.AspNetCore.SignalR.IClientProxy;

namespace IotClientApp.Server.Devices
{
    public class DeviceClient
    {
        public ConcurrentDictionary<string, DriverReturnValueModel> DriverValues = new ConcurrentDictionary<string, DriverReturnValueModel>();

        private ConcurrentDictionary<string, IClientProxy> HubClients = new ConcurrentDictionary<string, IClientProxy>();
        DeviceInfo device = null;
        CancellationTokenSource cancellation = new CancellationTokenSource();
        DeviceModBusMaster deviceModBusMaster;
        DeviceService deivceService;
        DeviceMQTTClient? deviceMQTTClient;
        /// <summary>
        /// 启动设备
        /// </summary>
        /// <param name="deviceInfo"></param>
        public async Task Start(DeviceModel deviceInfo)
        {
            #region mqtt客户端
            if (deviceInfo.MqttServer != null)
            {
                using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
                ILogger<DeviceMQTTClient> logger = factory.CreateLogger<DeviceMQTTClient>();
                deviceMQTTClient = new DeviceMQTTClient(logger);
                await deviceMQTTClient.Init(deviceInfo.DeviceId, deviceInfo.MqttServer.ServerIp, deviceInfo.MqttServer.Port, deviceInfo.MqttServer.AuthName, deviceInfo.MqttServer.AuthPwd, new List<DeviceTopicModel> { });
            }
            #endregion
            Task.Factory.StartNew(() =>
            {
                using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
                ILogger logger = factory.CreateLogger(typeof(DeviceModBusMaster));
                deviceModBusMaster = new DeviceModBusMaster(deviceInfo.DeviceId, logger);
                var port = deviceInfo.DeviceConfigs.First(t => t.DeviceConfigName == "Port").Value;
                var minPeriod = deviceInfo.DeviceConfigs.First(t => t.DeviceConfigName == "MinPeriod").Value;
                var ipAddress = deviceInfo.DeviceConfigs.First(t => t.DeviceConfigName == "IpAddress").Value;
                var slaveAddress = deviceInfo.DeviceConfigs.First(t => t.DeviceConfigName == "SlaveAddress").Value;
                deviceModBusMaster.MinPeriod = uint.Parse(minPeriod);
                deviceModBusMaster.IpAddress = ipAddress;
                deviceModBusMaster.SlaveAddress = byte.Parse(slaveAddress);
                deviceModBusMaster.Port = int.Parse(port);
                deviceModBusMaster.Connect();

                ILogger loggerDeivce = factory.CreateLogger<DeviceService>();
                device = new DeviceInfo
                {
                    AutoStart = deviceInfo.AutoStart,
                    DeviceName = deviceInfo.DeviceName,
                    DeviceVariables = new List<DeviceVariable> { }
                };
                foreach (var deviceVariable in deviceInfo.DeviceVariables)
                {
                    var multipleAddress1 = new DeviceVariable
                    {
                        Name = deviceVariable.Name,
                        EndianType = deviceVariable.EndianType,
                        Method = deviceVariable.Method,
                        DataType = deviceVariable.DataType,
                        DeviceAddress = deviceVariable.DeviceAddress
                    };
                    device.DeviceVariables.Add(multipleAddress1);
                }
                Action<List<DriverReturnValueModel>> a = async (realValues) =>
                {
                    foreach (var realValue in realValues)
                    {
                        if (deviceMQTTClient != null && realValue.StatusType == VaribaleStatusTypeEnum.Good)
                        {
                            deviceMQTTClient.Publish(deviceInfo.MqttServer.RealDataTopicName, JsonConvert.SerializeObject(realValue));
                        }
                        DriverValues.AddOrUpdate(realValue.Address, realValue, (key, value) =>
                        {
                            return realValue;
                        });
                        foreach (var hubClient in HubClients)
                        {
                            var msg = new RealDataModel
                            {
                                Name = realValue.Name,
                                Time = realValue.Timestamp
                            };
                            if (realValue.Value != null)
                            {
                                msg.Value = realValue.Value.ToString();
                            }
                            await hubClient.Value.SendAsync("ReceiveRealData", msg);
                        }
                    }
                };
                deivceService = new DeviceService(deviceModBusMaster, loggerDeivce, device, a);

            }, cancellation.Token);
        }
        public void Stop(string deviceId)
        {
            cancellation.Cancel();
            if (deviceModBusMaster != null)
            {
                deviceModBusMaster.Dispose();
            }
            if (deivceService != null)
            {
                deivceService.Dispose();
            }
        }
        public async Task<string> Control(int address, string value, DataTypeEnum dataType, EndianEnum endianEnum)
        {
            var r = await deviceModBusMaster.WriteAsync("", "HoldingRegisters", new DriverAddressIoArgModel
            {
                Address = $"{deviceModBusMaster.SlaveAddress}|{address}",
                Value = value,
                ValueType = dataType,
                EndianType = endianEnum
            });
            if (!r.IsSuccess)
            {
                return "error";
            }
            return "ok";
        }
        //public void Start()
        //{
        //    using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
        //    ILogger logger = factory.CreateLogger(typeof(DeviceModBusMaster));
        //    var deviceModBusMaster = new DeviceModBusMaster("m1", logger);
        //    deviceModBusMaster.MinPeriod = 1000;
        //    deviceModBusMaster.IpAddress = "127.0.0.1";
        //    deviceModBusMaster.SlaveAddress = 1;
        //    deviceModBusMaster.Port = 502;
        //    deviceModBusMaster.Connect();

        //    ILogger loggerDeivce = factory.CreateLogger<DeviceService>();
        //    device = new DeviceInfo
        //    {
        //        AutoStart = true,
        //        DeviceName = "我的Modbus",
        //        DriverId = Guid.NewGuid(),
        //        DeviceConfigs = new List<DeviceConfig>
        //        {
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="端口号",DeviceConfigName="Port",Value="502" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="主站类型",DeviceConfigName="MasterType",Value="Tcp",EnumInfo="{\"Tcp\":0,\"Udp\":1,\"Rtu\":2,\"RtuOnTcp\":3,\"RtuOnUdp\":4,\"Ascii\":5,\"AsciiOnTcp\":6,\"AsciiOnUdp\":7}" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="最小通讯周期ms",DeviceConfigName="MinPeriod",Value="0" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="超时时间ms",DeviceConfigName="Timeout",Value="3000" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="串口名",DeviceConfigName="PortName",Value="COM1" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="停止位",DeviceConfigName="StopBits",Value="One" ,EnumInfo="{\"None\":0,\"One\":1,\"Two\":2,\"OnePointFive\":3}" },
        //            //new DeviceConfig{ DataSide=DataSide.AnySide,Description="从站号",DeviceConfigName="SlaveAddress",Value="1" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="设备Id",DeviceConfigName="DeviceId" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="波特率",DeviceConfigName="BaudRate",Value="9600" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="数据位",DeviceConfigName="DataBits",Value="8" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="校验位",DeviceConfigName="Parity",Value="None",EnumInfo="{\"None\":0,\"Odd\":1,\"Even\":2,\"Mark\":3,\"Space\":4}" },
        //            new DeviceConfig{ DataSide=DataSide.AnySide,Description="IP地址",DeviceConfigName="IpAddress",Value="127.0.0.1" },
        //        },
        //        DeviceVariables = new List<DeviceVariable>
        //        {
        //            //new DeviceVariable{ Name="1号参数",Method="HoldingRegisters",DeviceAddress="0",DataType=DataTypeEnum.Int16,Index=0},
        //            //new DeviceVariable{ Name="4号参数",Method="HoldingRegisters",DeviceAddress="4",DataType=DataTypeEnum.Float,Index=1},
        //            //new DeviceVariable{ Name="3号参数",Method="HoldingRegisters",DeviceAddress="3",DataType=DataTypeEnum.Int16,Index=2},
        //            //new DeviceVariable{ Name="2号参数",Method="HoldingRegisters",DeviceAddress="1",DataType=DataTypeEnum.Int16,Index=4}
        //             new DeviceVariable{ Name="1号参数",Method="ReadMultiple",DeviceAddress="1|3,0,4,m1",DataType=DataTypeEnum.Int16,Index=0},
        //            new DeviceVariable{ Name="4号参数",Method="HoldingRegisters",DeviceAddress="4",DataType=DataTypeEnum.Float,Index=1}
        //        }
        //    };
        //    var multipleAddress = new DeviceVariable
        //    {
        //        Name = $"6125号参数",
        //        Method = "ReadMultiple",
        //        DataType = DataTypeEnum.Int16,
        //    };
        //    device.DeviceVariables.Add(multipleAddress);
        //    StringBuilder sbAddress = new StringBuilder();
        //    sbAddress.Append("1|");//slaveId，可以不填
        //    sbAddress.Append("3,6,125,m2");//功能,起始地址,长度,缓存名称
        //    multipleAddress.DeviceAddress = sbAddress.ToString();


        //    var paramVariables = new List<DeviceVariable> { };
        //    for (var i = 10; i < 1000; i++)
        //    {
        //        var multipleAddress1 = new DeviceVariable
        //        {
        //            Name = $"{i}号参数",
        //            Method = "HoldingRegisters",
        //            DataType = DataTypeEnum.Int16,
        //            DeviceAddress = i.ToString()
        //        };
        //        device.DeviceVariables.Add(multipleAddress1);
        //    }
        //    Action<List<DriverReturnValueModel>> a = async (realValues) =>
        //    {
        //        foreach (var realValue in realValues)
        //        {
        //            DriverValues.AddOrUpdate(realValue.Address, realValue, (key, value) =>
        //            {
        //                return realValue;
        //            });
        //            foreach (var hubClient in HubClients)
        //            {
        //                var msg = new RealDataModel
        //                {
        //                    Name = realValue.Address.ToString(),
        //                    Value = realValue.Value.ToString(),
        //                    Time = realValue.Timestamp
        //                };
        //                await hubClient.Value.SendAsync("ReceiveRealData", msg);
        //            }
        //        }
        //    };
        //    var deivceService = new DeviceService(deviceModBusMaster, loggerDeivce, device, a);
        //}

        public List<DriverReturnValueModel> GetValues(List<string> addrs)
        {
            var result = new List<DriverReturnValueModel> { };
            if (device != null && device.DeviceVariables != null)
            {
                var items = device.DeviceVariables.ToList();
                if (addrs.Count() > 0)
                {
                    items = items.Where(t => addrs.Contains(t.DeviceAddress)).ToList();
                }

                var values = DriverValues.Where(t => addrs.Contains(t.Key)).Select(t => t.Value).ToList();
                foreach(var item in items)
                {
                    var value = values.FirstOrDefault(t => t.Address == item.DeviceAddress);
                    if (value != null)
                    {
                        result.Add(value);
                    }
                    else
                    {
                        var r = new DriverReturnValueModel
                        {
                            Name=item.Name,
                            StatusType = item.StatusType,
                            Address = item.DeviceAddress
                        };
                        result.Add(r);
                    }
                }
            }
            return result;
        }

        public void SendToHubClient(string hubClientId, IClientProxy clientProxy)
        {
            HubClients.AddOrUpdate(hubClientId, clientProxy, (key, value) =>
            {
                return value;
            });
        }
        public void RemoveHubClient(string hubClientId)
        {
            HubClients.TryRemove(hubClientId, out _);
        }
    }
}